<!DOCTYPE html>
<!-- This test should be upstreamed to WPT but it was difficult to do so, see
     https://codereview.chromium.org/2869093002/ -->
<meta charset="utf-8">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/get-host-info.js?pipe=sub"></script>
<script src="resources/test-helpers.js"></script>
<title>Insecure parent frame test</title>
<body></body>
<script>
// Asks |worker| to call clients.claim. Returns a promise that resolves when
// the worker acks that claim finished.
function wait_for_claim(worker) {
  var saw_message = new Promise(resolve => {
      var channel = new MessageChannel();
      channel.port1.onmessage = (e => resolve(e.data));
      worker.postMessage({port: channel.port2}, [channel.port2]);
    });

  return saw_message.then(data => {
      assert_equals(data, 'PASS', 'claim should finish');
    });
}

// Asks |frame| whether it has a controller. Returns a promise that resolves
// if controller was null.
function assert_no_controller(frame, description) {
  var saw_message = new Promise(resolve => {
      window.onmessage = (e => resolve(e.data));
      frame.contentWindow.postMessage('', '*');
    });

  return saw_message.then(data => assert_equals(data, 'PASS', description));
}

// This test creates https iframes inside insecure http iframes. It registers a
// service worker that should not control the in-scope iframes. The iframes
// communicate whether they have a controller to the top-level frame.
promise_test(t => {
    var script = 'resources/claim-worker.js';
    var scope = 'resources/insecure-inscope';
    var registration;
    var insecure_url = get_host_info().UNAUTHENTICATED_ORIGIN +
              '/serviceworker/resources/insecure-parent.html';
    var pre_registration_frame;
    var post_registration_frame;

    return navigator.serviceWorker.getRegistration(scope)
      // Unregister.
      .then(reg => {
          if (reg)
            return reg.unregister();
        })

      // Create an iframe prior to registration.
      .then(() => with_iframe(insecure_url))

      // Register.
      .then(frame => {
          pre_registration_frame = frame;
          add_result_callback(() => pre_registration_frame.remove());
          return navigator.serviceWorker.register(script, {scope:scope});
        })
      .then(reg => {
          registration = reg;
          return wait_for_state(t, registration.installing, 'activated');
        })

      // Create an iframe after registration.
      .then(() => with_iframe(insecure_url))
      .then(frame => post_registration_frame = frame)

      // Check that no frame is controlled.
      .then(() => assert_no_controller(pre_registration_frame,
                      'pre_registration_frame should not be controlled'))
      .then(() => assert_no_controller(post_registration_frame,
                      'post_registration_frame should not be controlled'))

      // Attempt to claim. The iframes should still have no controllers.
      .then(() => wait_for_claim(registration.active))
      .then(() => assert_no_controller(pre_registration_frame,
                      'pre_registration_frame should not be claimed'))
      .then(() => assert_no_controller(post_registration_frame,
                      'post_registration_frame should not be claimed'));
  }, 'Service worker does not control a subframe of an insecure frame');
</script>
